
package org.nViron.nvGraffiti;

import instar.dg.Common.ID;
import instar.dg.Graffito.GraffitoHeader;
import instar.dg.Profile.Selection;

import java.util.Date;

import org.nViron.nvCommon.nvPosition;
import org.nViron.nvData.nvDataEntity;
import org.nViron.nvData.nvDataEntityMgr;
import org.nViron.nvParams.nvContextParamMgr.CONTEXTPARAM;

/**
 * DataEntity implementation that encapsulates the relevant information of a graffiti
 * @author Roland Haring <p>
 * <script type="text/javascript" src="http://www.ohloh.net/p/376434/widgets/project_basic_stats.js"></script>
 */
public class nvGraffitoEntity extends nvDataEntity {

    private GraffitoHeader graffitoHeader;
    private nvPosition position;
    private nvGraffitiSource graffitiSource;

    public nvGraffitoEntity(nvDataEntityMgr entityMgr, GraffitoHeader header, nvGraffitiSource source) {
        super(entityMgr);
        graffitiSource = source;
        // should be ok to use a reference ....
        graffitoHeader = header;
        //graffitoHeader = (GraffitoHeader)header.cloneMe();
        updateContext();
    }

     public float calculateContextValue(CONTEXTPARAM param) {
        float ret = 0.0f;
        // TODO implement, get all the values needed for update from nvDataEntityMg!!
        switch (param) {
            case ADDRESSE:
                ret = (isAddresse() ? 1.0f : 0.0f);
                break;
            case OTH_ADDRESSES:
                final float MAX_RECEIVERS = 5.0f;
                ret = graffitoHeader.receiver.length / MAX_RECEIVERS;
                break;
            case CREATOR:
                ret = (graffitoHeader.getAuthor().equals(graffitiSource.getID()) ? 1.0f : 0.0f);
                break;
            case ADDRESSE_FRIEND:
                ret = (isAddresseFriend() ? 1.0f : 0.0f);
                break;
            case CREATOR_FRIEND:
                ret = (graffitiSource.getBaseclient().getMe().getProfile().getAddressBook().containsFriend(graffitiSource.getID()) ? 1.0f : 0.0f);
                break;
            case CATEGORIES_SELECTED:
                ret = (isSelected() ? 1.0f : 0.0f);
                break;
            case CURSOR_DIST:
                final float MAX_CURSOR_DIST = 1000.0f;
                float cursorDist = (float)graffitiSource.getDataSourceMgr().getSimulator().getCursorPosition().getDistance2d(position);
                ret = 1.0f - cursorDist / MAX_CURSOR_DIST;
                break;
            case USER_DIST:
                final float MAX_USER_DIST = 1000.0f;
                float userDist = (float)graffitiSource.getDataSourceMgr().getSimulator().getUserPosition().getDistance2d(position);
                ret = 1.0f - userDist / MAX_USER_DIST;
                break;
            case SEARCH_RESULT:
                if (graffitiSource.getDataSourceMgr().getSimulator().getSearchString().length() > 0 && graffitoHeader.getSubject().matches(graffitiSource.getDataSourceMgr().getSimulator().getSearchString())) {
                    ret = 1.0f;
                }
                break;
            case AGE:
                final float MAX_AGE = 1000 * 60 * 60 * 24 * 365;
                ret = (new Date().getTime() - graffitoHeader.getCreationDate().getTime()) / MAX_AGE;
                break;
            case UNREAD:
                ret = (graffitoHeader.isAlreadyRead() ? 0.0f : 1.0f);
                break;
            case ALERT:
                ret = (graffitoHeader.isPopUp() && !graffitoHeader.getAuthor().equals(graffitiSource.getID())  ? 1.0f : 0.0f);
                break;
            case REMINDER:
                ret = (graffitoHeader.isPopUp() && graffitoHeader.getAuthor().equals(graffitiSource.getID())  ? 1.0f : 0.0f);
                break;
            case ORIENTATION:
                // TODO
                ret = (float)Math.random();
                break;
            case SELECTED:
                // TODO
                ret = (float)Math.random();
                break;
            // THOSE ARE NOT SUPPORTED
            case SELECTION_SIMILARITY:
            case POPULARITY:
            case RATING:
            case READ_FREQ:
            case USER_RATING:
            case DELTA_V:
            case REGIONALITY:
            case MIME_TYPE:
                ret = 0.0f;
                break;
        }

        // normalize
        if (ret > 1.0f) {
            ret = 1.0f;
        } else if (ret < 0.0f) {
            ret = 0.0f;
        }
        return ret;
    }

    public ID getGraffitoID() {
        return graffitoHeader.getId();
    }

    @Override
    public nvPosition getPosition() {
        return position;
    }

    private boolean isAddresse() {
        for (int i=0; i<graffitoHeader.receiver.length; i++) {
            if (graffitiSource.getID().equals(graffitoHeader.receiver[i])) {
                return true;
            }
        }
        return false;
    }

    private boolean isAddresseFriend() {
        for (int i=0; i<graffitoHeader.receiver.length; i++) {
            if (graffitiSource.getBaseclient().getMe().getProfile().getAddressBook().containsFriend(graffitoHeader.receiver[i])) {
                return true;
            }
        }
        return false;
    }

    private boolean isSelected() {
        for (int i=0; i<graffitoHeader.receiver.length; i++) {
            if ( graffitoHeader.receiver[i].getType() == ID.CATEGORY_TYPE) {
                Selection selection = graffitiSource.getBaseclient().getMe().getProfile().getSelection( graffitoHeader.receiver[i].getIdA() );
                if ( selection != null && selection.isSelected(graffitoHeader.receiver[i])) {
                    return true;
                }
            }
        }
        return false;
    }

    public void update(float timestamp2) {
        // TODO add update entities for UI and search interaction etc. (recalculate context for each entity)
    }

    private void updateContext() {
        // TODO graffiti altitude is currently ignored
        position = new nvPosition(graffitoHeader.getPosition().getLongitude(), graffitoHeader.getPosition().getLatitude(), 0 /*graffitoHeader.getPosition().getAltitude()*/);
        updateAllContextValues();
    }

}
